#include "circuitsimsystem.h"
#include <QtDebug>

#include "../aurasim.h"
#include "../entities/unoboardentity.h"

CircuitSimSystem::CircuitSimSystem(QObject* parent): System (parent)
{

}

void CircuitSimSystem::tick(const int &msec)
{
    Q_UNUSED(msec)
    if (Aurasim::app()->simState == Aurasim::Start)
        checkCircuitState();
}

void CircuitSimSystem::checkCircuitState()
{
    mValidCurrentLines.clear();
    mValidCurrentPinSet.clear();

    // find all valid current pin sequence
    findValidLines();

    // update new valid current pin set
    foreach(const QList<int>& line, mValidCurrentLines) {
        PinEntity* sourcePin = static_cast<PinEntity*>(Aurasim::entityManager()->getEntity(line[0]));
        qreal sourceVolt = sourcePin->volt();

        foreach(const int& id, line) {
            PinEntity* pin = static_cast<PinEntity*>(Aurasim::entityManager()->getEntity(id));
            if(pin)
                pin->setVolt(sourceVolt);

            mValidCurrentPinSet.insert(id);
        }
    }

    // update which pin has passing current.
    foreach(Entity* e, Aurasim::entityManager()->entities()) {
        PinEntity* pin = static_cast<PinEntity*>(e);
        if(pin) {
            pin->setHasCurrent(mValidCurrentPinSet.contains(pin->id()));
        }
    }
}

void CircuitSimSystem::findValidLines()
{
    // find all output pins as source pins.
    foreach (Entity* e, Aurasim::entityManager()->entities()) {
        if(e->name() == "Pin" || e->name() == "RoundPin") {
            PinEntity* pin = static_cast<PinEntity*>(e);
            if (pin && pin->pinMode() == 1) {
                QList<int> line;
                findNodes(line, pin->id());
            }
        }
    }
}

void CircuitSimSystem::findNodes(QList<int> &line, const int &pinID)
{
    line.append(pinID);
    PinEntity* pin = static_cast<PinEntity*>(Aurasim::entityManager()->getEntity(pinID));

    if(!pin || Aurasim::app()->simState == Aurasim::Stop)
        return;

    if(pin->pinMode() == 2) {
        mValidCurrentLines.append(line);
        return;
    }
    foreach(const int& nextID, pin->currentNodes()) {
        QList<int> subLine = line;
        findNodes(subLine, nextID);
    }
}
